﻿using ICSharpCode.AvalonEdit.CodeCompletion;
using IronPython.Runtime.Operations;
using Microsoft.Scripting.Utils;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Media.Imaging;
using Xceed.Wpf.Toolkit.PropertyGrid;

namespace LunarSF.SHomeWorkshop.LunarMarkdownEditor.PythonHelp.CompleteKeywords
{
    /// <summary>
    /// 这个例用单例模式。
    /// </summary>
    internal class CompleteInfoManager
    {
        private CompleteInfoManager() { }

        private static CompleteInfoManager singleManager;

        public static CompleteInfoManager SingleManager { get { return singleManager; } }

        static CompleteInfoManager()
        {
            obsIcon = new BitmapImage(new Uri("pack://application:,,,/LunarMarkdownEditor;component/Images/CloseHS.png"));

            classIcon = new BitmapImage(new Uri("pack://application:,,,/LunarMarkdownEditor;component/Images/PythonEditorIcons/class.png"));
            cons_funcIcon = new BitmapImage(new Uri("pack://application:,,,/LunarMarkdownEditor;component/Images/PythonEditorIcons/cons_func.png"));
            enumIcon = new BitmapImage(new Uri("pack://application:,,,/LunarMarkdownEditor;component/Images/PythonEditorIcons/enum.png"));
            enum_valueIcon = new BitmapImage(new Uri("pack://application:,,,/LunarMarkdownEditor;component/Images/PythonEditorIcons/enum_value.png"));
            inner_funcIcon = new BitmapImage(new Uri("pack://application:,,,/LunarMarkdownEditor;component/Images/PythonEditorIcons/inner_func.png"));
            instance_funcIcon = new BitmapImage(new Uri("pack://application:,,,/LunarMarkdownEditor;component/Images/PythonEditorIcons/instance_func.png"));
            instance_propertyIcon = new BitmapImage(new Uri("pack://application:,,,/LunarMarkdownEditor;component/Images/PythonEditorIcons/instance_property.png"));
            static_funcIcon = new BitmapImage(new Uri("pack://application:,,,/LunarMarkdownEditor;component/Images/PythonEditorIcons/static_func.png"));
            static_propertyIcon = new BitmapImage(new Uri("pack://application:,,,/LunarMarkdownEditor;component/Images/PythonEditorIcons/static_property.png"));

            singleManager = new CompleteInfoManager();
            singleManager.ReloadCompleteKeywordInfos();
        }

        #region 用以区别不同类别智能提示条目的图标
        private static BitmapImage obsIcon;
        /// <summary>
        /// 废弃关键词图标。
        /// </summary>
        public static BitmapImage ObsIcon { get => obsIcon; }

        private static BitmapImage classIcon;
        public static BitmapSource ClassIcon { get => classIcon; }

        private static BitmapImage cons_funcIcon;
        public static BitmapSource Cons_funcIcon { get => cons_funcIcon; }

        private static BitmapImage enumIcon;
        public static BitmapSource EnumIcon { get => enumIcon; }

        private static BitmapImage enum_valueIcon;
        public static BitmapSource Enum_valueIcon { get => enum_valueIcon; }

        private static BitmapImage inner_funcIcon;
        public static BitmapSource Inner_funcIcon { get => inner_funcIcon; }

        private static BitmapImage instance_funcIcon;
        public static BitmapSource Instance_funcIcon { get => instance_funcIcon; }

        private static BitmapImage instance_propertyIcon;
        public static BitmapSource Instance_propertyIcon { get => instance_propertyIcon; }

        private static BitmapImage static_funcIcon;
        public static BitmapSource Static_funcIcon { get => static_funcIcon; }

        private static BitmapImage static_propertyIcon;
        public static BitmapSource Static_propertyIcon { get => static_propertyIcon; }
        #endregion

        private List<CompleteKeywordInfo> completeKeywordInfos = new List<CompleteKeywordInfo>();

        public void ReloadCompleteKeywordInfos()
        {
            this.completeKeywordInfos.Clear();

            var dir = Globals.PythonCompleteKeywordsFolderPath;

            if (Directory.Exists(dir) == false) return;

            var files = Directory.GetFiles(dir, "*.txt", SearchOption.TopDirectoryOnly);
            foreach (var file in files)
            {
                using (var sr = new StreamReader(file))
                {
                    var text = sr.ReadToEnd().replace("\r\n^", "<br>");
                    string[] pieces;
                    pieces = text.Split(new string[] { "\r\n===", "\r\n---", "\r\n//---", "\r\n//---" }, StringSplitOptions.RemoveEmptyEntries);

                    if (pieces.Length <= 0) continue;

                    foreach (var piece in pieces)
                    {
                        var lines = piece.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
                        var info = new CompleteKeywordInfo();
                        foreach (var line in lines)
                        {
                            if (line.Length >= 1 && "-=;；#/".Contains(line[0])) continue;
                            var index = line.IndexOf("】");
                            if (index == -1) continue;

                            var header = line.Substring(0, index).Trim(new char[] { ' ', '【', '　', '\t' });

                            switch (header)
                            {
                                case "关键字":
                                case "关键词":
                                    {
                                        info.Keyword = line.Substring(index + 1).Trim();
                                        break;
                                    }
                                case "说明":
                                case "描述":
                                    {
                                        info.Description = line.Substring(index + 1).Trim();
                                        break;
                                    }
                                case "参数":
                                    {
                                        var tail = line.Substring(index + 1).Trim();
                                        if (tail.StartsWith("数值。"))
                                        {
                                            info.Args.Add(new ArgInfo()
                                            {
                                                ArgType = ArgType.Number,
                                                ArgDescription = tail.Substring(3),
                                            });
                                        }
                                        else if (tail.StartsWith("文本。"))
                                        {
                                            info.Args.Add(new ArgInfo()
                                            {
                                                ArgType = ArgType.String,
                                                ArgDescription = tail.Substring(3),
                                            });
                                        }
                                        else if (tail.StartsWith("原文本。"))
                                        {
                                            info.Args.Add(new ArgInfo()
                                            {
                                                ArgType = ArgType.RString,
                                                ArgDescription = tail.Substring(4),
                                            });
                                        }
                                        else if (tail.StartsWith("逻辑。") || tail.StartsWith("真假。"))
                                        {
                                            info.Args.Add(new ArgInfo()
                                            {
                                                ArgType = ArgType.Bool,
                                                ArgDescription = tail.Substring(3),
                                            });
                                        }
                                        else if (tail.StartsWith("对象。"))
                                        {
                                            info.Args.Add(new ArgInfo()
                                            {
                                                ArgType = ArgType.Object,
                                                ArgDescription = tail.Substring(3),
                                            });
                                        }
                                        else if (tail.StartsWith("枚举。"))
                                        {
                                            info.Args.Add(new ArgInfo()
                                            {
                                                ArgType = ArgType.EnumValue,
                                                ArgDescription = tail.Substring(3),
                                            });
                                        }
                                        break;
                                    }
                                case "返回":
                                case "返回值":
                                    {
                                        info.ReturnValueDescription = line.Substring(index + 1).Trim();
                                        break;
                                    }
                                case "类型":
                                    {
                                        var tail = line.Substring(index + 1).Trim(new char[] { ' ', '　', '\t', '。' });
                                        if (tail == "方法" || tail == "函数" || tail == "实例方法")
                                        {
                                            info.Type = KeywordType.MethodKeyword;
                                        }
                                        else if (tail == "静态方法" || tail == "静态函数")
                                        {
                                            info.Type = KeywordType.StaticMethodKeyword;
                                        }
                                        else if (tail == "静态属性")
                                        {
                                            info.Type = KeywordType.StaticPropertyKeyword;
                                        }
                                        else if (tail == "构造方法")
                                        {
                                            info.Type = KeywordType.ConstructionMethod;
                                        }
                                        else if (tail == "内置函数" || tail == "内置方法")
                                        {
                                            info.Type = KeywordType.InnerFunction;
                                        }
                                        else if (tail == "类")
                                        {
                                            info.Type = KeywordType.Class;
                                        }
                                        else if (tail == "枚举类型" || tail == "枚举")
                                        {
                                            info.Type = KeywordType.EnumType;
                                        }
                                        else if (tail == "枚举值")
                                        {
                                            info.Type = KeywordType.EnumValue;
                                        }
                                        else
                                        {
                                            info.Type = KeywordType.PropertyKeyword;
                                        }
                                        break;
                                    }
                            }
                        }

                        if (string.IsNullOrWhiteSpace(info.Keyword) == false)
                        {
                            var keySpans = info.Keyword.Split(new char[] { ',', ' ', '　', '\t', '|', '｜' }, StringSplitOptions.RemoveEmptyEntries);
                            if (keySpans.Length == 2)
                            {
                                info.Keyword = keySpans[0];
                                var info2 = new CompleteKeywordInfo()
                                {
                                    Keyword = keySpans[1],
                                    Args = info.Args,
                                    Description = info.Description,
                                    ReturnValueDescription = info.ReturnValueDescription,
                                    Type = info.Type
                                };

                                this.completeKeywordInfos.Add(info);
                                this.completeKeywordInfos.Add(info2);
                            }
                            else
                            {
                                this.completeKeywordInfos.Add(info);
                            }
                        }
                    }
                }
            }

#if DEBUG
            
            var sb = new StringBuilder();
            foreach(var c in this.completeKeywordInfos){
                sb.Append(c.Keyword);
                sb.Append("\r\n");
            }
            // File.WriteAllText(@"d:\aaa\keywords.txt", sb.ToString());

            Type[] types = typeof(LunarSF.SHomeWorkshop.LunarMarkdownEditor.Utils.NPOIHelp.区域).Assembly.GetTypes();
            var sb2 = new StringBuilder();
            var reg = new Regex(@"^[a-zA-Z0-9_]{1,}$");
            foreach(var type in types)
            {
                PropertyInfo[] properties = type.GetProperties();
                foreach(var property in properties)
                {
                    if (property.IsPublic())
                    {
                        if (reg.Match(property.Name).Success) continue;  // 纯英文的不要
                        sb2.Append(property.Name);
                        sb2.Append("\r\n");
                    }
                }

                MethodInfo[] methods = type.GetMethods();
                foreach(var method in methods)
                {
                    if (method.IsPublic)
                    {
                        if (reg.Match(method.Name).Success) continue;  // 纯英文的不要
                        sb2.Append(method.Name); sb2.Append("\r\n");
                    }
                }
            }
            // File.WriteAllText(@"d:\aaa\proandmethods.txt", sb2.ToString());
#endif
        }

        public event EventHandler<CompleteInfoReloadedArgs> ReLoaded;

        public void OnReloaded()
        {
            if (ReLoaded != null)
            {
                ReLoaded(this, new CompleteInfoReloadedArgs(this.completeKeywordInfos));
            }
        }

        private List<CustomCompletionData> completionDatas = new List<CustomCompletionData>();

        public List<CustomCompletionData> CompletionDatas { get { return completionDatas; } }

        public void BuildCompletionDataList()
        {
            completionDatas.Clear();

            var regConstruct = new Regex(@"(?<=“).*?(?=(”类的构造(方法|函数)))");
            var regModel = new Regex(@".*(?=( ?模块内置(方法|属性)))");
            var regPython = new Regex(@"Python(?=( ?(集合|内置)(函数|方法)))");
            var regInstalce = new Regex(@"(?<=((由|通过)“)).*?(?=(”类的实例调用))");
            var regClass = new Regex(@"(?<=((由|通过)“)).*?(?=(”类调用))");
            var regEnum = new Regex(@"(?<=((由|通过)“)).*?(?=(”枚举调用))");
            var regPsArgs = new Regex(@"(?<=((由|通过)“))psArgs(?=(”全局实例调用))");
            var regObject = new Regex(@"(?<=((由|通过)“)).*?(?=(”对象调用))");

            foreach (var info in this.completeKeywordInfos)
            {
                if (string.IsNullOrWhiteSpace(info.Keyword)) continue;

                CustomCompletionData citem;
                var matchCaller = regConstruct.Match(info.FullDescription);
                if (matchCaller.Success && matchCaller.Length > 0)
                {
                    citem = new CustomCompletionData(info.Keyword, info.FullDescription, info.CompleteText, " < [" + matchCaller.Value + "] 类构造", System.Windows.Media.Brushes.Red)
                    {
                        BackSelectOffset = info.BackSelectOffset,
                        IsObsoleting = info.IsObsoleting,
                    };
                }
                else
                {
                    matchCaller = regModel.Match(info.FullDescription);
                    if (matchCaller.Success && matchCaller.Length > 0)
                    {
                        citem = new CustomCompletionData(info.Keyword, info.FullDescription, info.CompleteText, " < [" + matchCaller.Value + "] 模块", System.Windows.Media.Brushes.YellowGreen)
                        {
                            BackSelectOffset = info.BackSelectOffset,
                            IsObsoleting = info.IsObsoleting,
                        };
                    }
                    else
                    {
                        matchCaller = regPython.Match(info.FullDescription);
                        if (matchCaller.Success && matchCaller.Length > 0)
                        {
                            citem = new CustomCompletionData(info.Keyword, info.FullDescription, info.CompleteText, " < [" + matchCaller.Value + "] 内置", System.Windows.Media.Brushes.Violet)
                            {
                                BackSelectOffset = info.BackSelectOffset,
                                IsObsoleting = info.IsObsoleting,
                            };
                        }
                        else
                        {
                            matchCaller = regInstalce.Match(info.FullDescription);
                            if (matchCaller.Success && matchCaller.Length > 0)
                            {
                                citem = new CustomCompletionData(info.Keyword, info.FullDescription, info.CompleteText, " < [" + matchCaller.Value + "] 类实例", System.Windows.Media.Brushes.Green)
                                {
                                    BackSelectOffset = info.BackSelectOffset,
                                    IsObsoleting = info.IsObsoleting,
                                };
                            }
                            else
                            {
                                matchCaller = regClass.Match(info.FullDescription);
                                if (matchCaller.Success && matchCaller.Length > 0)
                                {
                                    citem = new CustomCompletionData(info.Keyword, info.FullDescription, info.CompleteText, " < [" + matchCaller.Value + "] 类", System.Windows.Media.Brushes.Gray)
                                    {
                                        PrefixClassName = matchCaller.Value,
                                        BackSelectOffset = info.BackSelectOffset,
                                        IsObsoleting = info.IsObsoleting,
                                    };
                                }
                                else
                                {
                                    matchCaller = regEnum.Match(info.FullDescription);
                                    if (matchCaller.Success && matchCaller.Length > 0)
                                    {
                                        citem = new CustomCompletionData(info.Keyword, info.FullDescription, info.CompleteText, " < [" + matchCaller.Value + "] 枚举", System.Windows.Media.Brushes.Blue)
                                        {
                                            BackSelectOffset = info.BackSelectOffset,
                                            IsObsoleting = info.IsObsoleting,
                                        };
                                    }
                                    else
                                    {
                                        matchCaller = regPsArgs.Match(info.FullDescription);
                                        if (matchCaller.Success && matchCaller.Length > 0)
                                        {
                                            citem = new CustomCompletionData(info.Keyword, info.FullDescription, info.CompleteText, " < [" + matchCaller.Value + "] 参数", System.Windows.Media.Brushes.Chocolate)
                                            {
                                                BackSelectOffset = info.BackSelectOffset,
                                                IsObsoleting = info.IsObsoleting,
                                            };
                                        }
                                        else
                                        {
                                            matchCaller = regObject.Match(info.FullDescription);
                                            if (matchCaller.Success && matchCaller.Length > 0)
                                            {
                                                citem = new CustomCompletionData(info.Keyword, info.FullDescription, info.CompleteText, " < [" + matchCaller.Value + "] 对象", System.Windows.Media.Brushes.CadetBlue)
                                                {
                                                    BackSelectOffset = info.BackSelectOffset,
                                                    IsObsoleting = info.IsObsoleting,
                                                };
                                            }
                                            else
                                            {
                                                citem = new CustomCompletionData(info.Keyword, info.FullDescription, info.CompleteText, " < (其它)", System.Windows.Media.Brushes.DeepPink)
                                                {
                                                    BackSelectOffset = info.BackSelectOffset,
                                                    IsObsoleting = info.IsObsoleting,
                                                };
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }

                if (info.IsObsoleting)
                {
                    citem.Image = obsIcon;
                }
                else
                {
                    switch (info.Type)
                    {
                        case KeywordType.PropertyKeyword:
                            citem.Image = instance_propertyIcon;
                            break;
                        case KeywordType.StaticPropertyKeyword:
                            citem.Image = static_propertyIcon;
                            break;
                        case KeywordType.MethodKeyword:
                            citem.Image = instance_funcIcon;
                            break;
                        case KeywordType.StaticMethodKeyword:
                            citem.Image = static_funcIcon;
                            break;
                        case KeywordType.ConstructionMethod:
                            citem.Image = cons_funcIcon;
                            break;
                        case KeywordType.InnerFunction:
                            citem.Image = inner_funcIcon;
                            break;
                        case KeywordType.Class:
                            citem.Image = classIcon;
                            break;
                        case KeywordType.EnumType:
                            citem.Image = enumIcon;
                            break;
                        case KeywordType.EnumValue:
                            citem.Image = enum_valueIcon;
                            break;
                    }
                }

                this.completionDatas.Add(citem);
            }
        }
    }

    internal class CompleteInfoReloadedArgs : EventArgs
    {
        public CompleteInfoReloadedArgs(List<CompleteKeywordInfo> completeKeywordInfos)
        {
            this.completeKeywordInfos = completeKeywordInfos;
        }

        private List<CompleteKeywordInfo> completeKeywordInfos;

        public List<CompleteKeywordInfo> CompleteKeywordInfos
        {
            get { return completeKeywordInfos; }
        }
    }
}
